package it.dk.model;

import org.newdawn.slick.geom.*;

/**
 * Rappresenta la classe che consente di gestire il personaggio principale del gioco.
 * 
 * Pattern utilizzato: Singleton 
 */
public class Hero extends DynamicGameObject{

	static private Hero instance = null;
	private HeroState state;
	private Shape innerShape;
	
	/**
	 * Costruttore privato vuoto della classe (richiesto dal pattern singleton)
	 */
	private Hero(){
		super();
	}
	
	/**
	 * Metodo utilizzato per restituire l'unica istanza della classe
	 * (richiesto per l'implementazione del pattern singleton)
	 * 
	 * @return	l'unica istanza della classe
	 */
	public static Hero getInstance(){
		if(instance==null){
			instance = new Hero();
		}
		return instance;
	}
	
	/**
	 * Metodo che inizializza l'unica istanza della classe
	 * 
	 * @param shape		shape di hero, utilizzata per la gestione
	 * 					delle collisioni e per contenere l'immagine
	 * @param innerShape		shape interna pi� piccola di hero,utilizzata per gestire
	 * 							particolari collisioni
	 * @param speedX	velocit� di hero lungo l'asse x
	 * @param speedY	velocit� di hero lungo l'asse y
	 * @param gravity	accelerazione di gravit� a cui � soggetto hero
	 */
	public void init(Shape shape, Shape core, float speedX, float speedY, float gravity){
		this.shape = shape;
		this.innerShape = core;
		this.defaultSpeedX = speedX;
		this.defaultSpeedY = speedY;
		this.gravity = gravity;
		this.actualSpeedX = 0;
		this.actualSpeedY = 0;
		state = new HeroStateLeftMovement(new HeroStateRightMovement(new HeroStateBase(this)));
	}
	
	/**
	 * Metodo getter per la shape interna pi� piccola
	 * 
	 * @return	shape interna pi� piccola
	 */
	public Shape getInnerShape(){
		return innerShape;
	}
	
	/**
	 * Metodo getter per il bordo inferiore della shape dell'hero
	 * 
	 * @return	bordo inferiore della shape dell'hero
	 */
	public Rectangle getBottomBorder(){
		return new Rectangle(innerShape.getX(), innerShape.getY() + innerShape.getHeight(), innerShape.getWidth(), 1);
	}
	
	/**
	 * Metodo setter per lo stato in cui si trova l'hero
	 * 
	 * @param newHeroState	nuovo stato in cui si trova l'hero
	 */
	public void setState(HeroState newHeroState){
		state = newHeroState;
	}
	
	/**
	 * Metodo getter per lo stato in cui si trova l'hero
	 * 
	 * @return lo stato in cui si trova l'hero
	 */
	public HeroState getState(){
		return state;
	}
	
	/**
	 * Metodo che esegue la movimentazione verso il basso dell'hero
	 * 
	 * @param delta		periodo di refresh del gioco, viene utilizzato
	 * 					per pesare gli spostamenti
	 */
	public void moveDown(int delta){
		state.moveDown(delta);
	}
	
	/**
	 * Metodo che esegue la movimentazione verso sinistra dell'hero
	 * 
	 * @param delta		periodo di refresh del gioco, viene utilizzato
	 * 					per pesare gli spostamenti
	 */
	public void moveLeft(int delta){
		state.moveLeft(delta);
	}
	
	/**
	 * Metodo che esegue la movimentazione verso destra dell'hero
	 * 
	 * @param delta		periodo di refresh del gioco, viene utilizzato
	 * 					per pesare gli spostamenti
	 */
	public void moveRight(int delta){
		state.moveRight(delta);
	}
	
	/**
	 * Metodo che esegue la movimentazione verso l'alto dell'hero
	 * 
	 * @param delta		periodo di refresh del gioco, viene utilizzato
	 * 					per pesare gli spostamenti
	 */
	public void moveUp(int delta){
		state.moveUp(delta);
	}
	
	/**
	 * Metodo che esegue la movimentazione per il salto dell'hero
	 * 
	 * @param delta		periodo di refresh del gioco, viene utilizzato
	 * 					per pesare gli spostamenti
	 * @param speedX	parametro che indica il verso e la presenza di
	 * 					velocit� orizzontale durante il salto
	 * 					i possibili valori sono:
	 * 					> -1	salto parabolico versop sinistra
	 * 					>  0	salto sul posto
	 * 					> +1	salto parabolico verso destra
	 */
	public void jump(int delta, int speedX){
		state.jump(delta, speedX);
	}
}
